<script lang="ts" setup>
import type Node from "element-plus/es/components/tree/src/model/node";
import { initMenu } from "@/data/menu";
import { SForm } from "#components";

// 使用索引签名定义对象类型
type GenericObject = {
  [key: string]: any;
};
interface Tree {
  label: string;
  path: string;
  icon?: string;
  noChild: boolean;
  children?: Tree[];
}

const editMenuFormRef = ref<InstanceType<typeof SForm> | null>(null);
const callbackMessage = useCallbackMessage();
const callbackMessage_dialog = useCallbackMessage();
let old_unique = "";
const PageConfig = {
  //被操作实体的名称
  entity: "system",
  api: {
    //获取列表数据
    list: "/list",
  },
};
const action = ref("list");
const id = ref("");
const addType = ref("");
const Model: {
  [key: string]: any;
} = {
  label: {
    label: "菜单名称",
    require: true,
  },
  path: {
    label: "菜单路径",
    require: true,
  },
  icon: {
    label: "菜单图标",
  },
  noChild: {
    label: "页面菜单",
    type: "switch",
  },
};
const dataSource = ref<GenericObject[]>([]);
let handle_data: GenericObject = {};
const dialogVisible = ref(false);

onMounted(() => {
  getList();
});

const getList = async () => {
  action.value = "list";
  const res: {
    [key: string]: any;
  }[] = await $fetch(`/api/${PageConfig.entity}${PageConfig.api.list}`, {
    query: {
      name: "menu",
    },
  });
  if (Array.isArray(res) && res.length > 0) {
    dataSource.value = JSON.parse(res[0].content);
    id.value = res[0]._id;
  } else {
    try {
      await $fetch(`/api/system/add`, {
        body: {
          name: "menu",
          content: JSON.stringify(initMenu),
        },
        method: "POST",
      });
      saveOK();
    } catch (e: any) {
      callbackMessage.value = {
        show: true,
        valid: false,
        content: "菜单初始化失败",
      };
    }
  }
};

// 按钮--添加（子菜单）
const handle_add = async (data: Tree, node: Tree) => {
  action.value = "add";
  addType.value = "addChild";
  dialogVisible.value = true;
  old_unique = "";
  handle_data = data;
  await nextTick();
  if (editMenuFormRef.value) {
    editMenuFormRef.value.localFormData = {};
  }
};

// 按钮-编辑
const handle_edit = async (data: Tree) => {
  action.value = "edit";
  addType.value = "";
  dialogVisible.value = true;
  old_unique = data.path;
  handle_data = data;
  await nextTick();
  if (editMenuFormRef.value) {
    editMenuFormRef.value.localFormData = JSON.parse(JSON.stringify(data));
  }
};

// 按钮--删除
const handle_del = (node: Node, data: Tree) => {
  const parent = node.parent;
  const children: Tree[] = parent.data.children || parent.data;
  const index = children.findIndex((d) => d.path === data.path);
  children.splice(index, 1);
  dataSource.value = [...dataSource.value];
  saveToDB();
};

// 按钮--添加顶级菜单
const addTop = () => {
  action.value = "add";
  addType.value = "addTop";
  if (editMenuFormRef.value) {
    editMenuFormRef.value!.localFormData = {};
  }
  dialogVisible.value = true;
};

// 弹窗按钮--保存
const save = async () => {
  if (editMenuFormRef.value) {
    let new_unique = editMenuFormRef.value.localFormData.path;
    if (
      old_unique !== new_unique &&
      hasTargetValueInTree(dataSource.value, "path", new_unique)
    ) {
      callbackMessage_dialog.value = {
        show: true,
        valid: false,
        content: "菜单路径已存在，请修改后重试",
      };
      return;
    }
    editMenuFormRef.value.submitForm(editMenuFormRef.value.formRef);
  }
};

// 保存到数据库
const saveToDB = async (formData?: GenericObject) => {
  let old_dataSource = JSON.parse(JSON.stringify(dataSource.value));
  if (formData) {
    if (addType.value === "addTop") {
      dataSource.value.unshift(formData);
    }
    if (addType.value === "addChild") {
      const newChild = formData;
      if (!handle_data.children) {
        handle_data.children = [];
      }
      handle_data.children.push(newChild);
    }
    if (action.value === "edit") {
      handle_data.label = formData.label;
      handle_data.path = formData.path;
      handle_data.icon = formData.icon;
      handle_data.noChild = formData.noChild;
    }
  }
  try {
    await $fetch(`/api/system/edit`, {
      body: {
        _id: id.value,
        name: "menu",
        content: JSON.stringify(dataSource.value),
      },
      method: "POST",
    });
    callbackMessage.value = {
      show: true,
      valid: true,
      content: "操作成功",
    };
    saveOK();
  } catch (e: any) {
    callbackMessage.value = {
      show: true,
      valid: false,
      content: e.data.message,
    };
    dataSource.value = JSON.parse(JSON.stringify(old_dataSource));
  }
};

// 保存成功后的回调 -- 刷新菜单
const saveOK = () => {
  addType.value === "";
  getList();
  setTimeout(() => {
    dialogVisible.value = false;
  }, 500);
};

// 拖拽菜单后，将新菜单保存到数据库
const handle_drop = async () => {
  saveToDB();
};
</script>
<template>
  <div class="flex flex-col items-center fullParent overflow-auto pt-10">
    <el-dialog v-model="dialogVisible" width="600" title="编辑菜单">
      <S-form
        ref="editMenuFormRef"
        hideHandle
        :Model="Model"
        :colNum="1"
        :local_save="saveToDB"
      />
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="dialogVisible = false">取消</el-button>
          <el-button type="primary" @click="save"> 保存 </el-button>
        </div>
      </template>
      <S-msgWin top="20%" :msg="callbackMessage_dialog" />
    </el-dialog>
    <el-button type="primary" @click="addTop"> 添加顶级菜单 </el-button>
    <el-tree
      class="mt4"
      style="min-width: 600px"
      :data="dataSource"
      node-key="path"
      accordion
      draggable
      default-expand-all
      :expand-on-click-node="false"
      :indent="40"
      @node-drop="handle_drop"
    >
      <template #default="{ node, data }">
        <div class="custom-tree-node">
          <div
            class="flex items-center gap-2"
            :class="{
              'font-bold': node.level === 1,
              'text-4': node.level === 1,
            }"
          >
            <S-icon v-if="data.icon" :icon="data.icon" />
            <div>
              {{ node.label }}
            </div>
          </div>
          <div>
            <el-button
              type="primary"
              link
              @click="handle_add(data, node)"
              :disabled="data.noChild"
            >
              <S-icon icon="material-symbols-light:add-rounded" />
              <span class="ml2">添加</span>
            </el-button>
            <el-button
              class="ml4"
              type="primary"
              link
              @click="handle_edit(data)"
            >
              <S-icon icon="line-md:edit-twotone" />
              <span class="ml2">修改</span>
            </el-button>
            <el-popconfirm
              title="确定删除吗?"
              @confirm="handle_del(node, data)"
            >
              <template #reference>
                <el-button class="ml4" type="danger" link>
                  <S-icon icon="wpf:delete" />
                  <span class="ml2">删除</span>
                </el-button>
              </template>
            </el-popconfirm>
          </div>
        </div>
      </template>
    </el-tree>
    <S-msgWin top="20%" :msg="callbackMessage" />
  </div>
</template>
<style scoped>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
.fullParent {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}
:deep(.el-tree-node) {
  margin-top: 12px;
}
</style>
